package inf.main;

/*
 * Class offering the inf.main functions of the library
 * @author M.T. Segarra
 * @version 0.0.1
 */

import inf.booksManagement.Book;
import inf.dvdsManagement.Dvd;
import inf.exceptions.*;
import inf.hibernateUtils.HibernateUtil;
import inf.loansManagement.Booking;
import inf.loansManagement.Loan;
import inf.mediasManagement.Media;
import inf.mediasManagement.MediaDAO;
import inf.outils.StringCalendar;
import inf.specimensManagement.Specimen;
import inf.subscribersManagement.Subscriber;
import inf.subscribersManagement.SubscriberDAO;

import java.util.*;

import org.hibernate.Session;
import org.hibernate.Transaction;



/**
 * @author  Ambroise
 */
public class Library {

	/**
	 * @uml.property  name="sc"
	 * @uml.associationEnd  
	 */
	private StringCalendar sc=new StringCalendar();

	/**
	 * @uml.property  name="loans"
	 * @uml.associationEnd  multiplicity="(0 -1)" ordering="true" inverse="library:inf.loansManagement.Loan"
	 */
	private ArrayList<Loan> loans = new ArrayList<Loan>();
	
	private ArrayList<Booking> bookings = new ArrayList<Booking>();;

	/**
	 * @uml.property  name="medias"
	 * @uml.associationEnd  multiplicity="(0 -1)" ordering="true" inverse="library:inf.mediasManagement.Media"
	 */
	private ArrayList<Media> medias = new ArrayList<Media>();

	/**
	 * @uml.property  name="subscribers"
	 * @uml.associationEnd  multiplicity="(0 -1)" ordering="true" inverse="library:inf.subscribersManagement.Subscriber"
	 */
	private ArrayList<Subscriber> subscribers = new ArrayList<Subscriber>();


	//Accessors
	/**
	 * @return
	 * @uml.property  name="medias"
	 */
	public ArrayList<Media> getMedias() {
		return medias;
	}

	public Media getMedia(int index) {
		return medias.get(index);
	}

	/**
	 * @return
	 * @uml.property  name="loans"
	 */
	public ArrayList<Loan> getLoans() {
		return loans;
	}

	public Loan getLoan(int index) {
		return loans.get(index);
	}


	/**
	 * @param loans
	 * @uml.property  name="loans"
	 */
	public void setLoans(ArrayList<Loan> loans) {
		this.loans = loans;
	}

	/**
	 * @return
	 * @uml.property  name="subscribers"
	 */
	public ArrayList<Subscriber> getSubscribers() {
		return subscribers;
	}

	public Subscriber getSubscriber(int index) {
		return subscribers.get(index);
	}

	/**
	 * @param subscribers
	 * @uml.property  name="subscribers"
	 */
	public void setSubscribers(ArrayList<Subscriber> subscribers) {
		this.subscribers = subscribers;
	}

	/**
	 * @param medias
	 * @uml.property  name="medias"
	 */
	public void setMedias(ArrayList<Media> medias) {
		this.medias = medias;
	}

	/**
	 * @throws BadParametersException 
	 * @throws MediaExistsException 
	 */
	public Boolean isAMedia(Media media) throws BadParametersException, MediaExistsException{
		if (media == null)
			throw new BadParametersException();

		// If the object is in the list,
		// it is a known media
		return inf.mediasManagement.MediaDAO.contains(media);
	}

	/**
	 * A utility method to know if a subscriber is known of the library
	 * 
	 * @param subscriber to
	 * @return false if the subscriber of the parameter is not known of the library
	 * @return true if the subscriber of the parameter is known of the library
	 * @throws MediaExistsException 
	 */
	private boolean isASubscriber(Subscriber subscriber) throws BadParametersException, SubscriberExistsException, MediaExistsException {
		if (subscriber == null)
			throw new BadParametersException();
		return inf.subscribersManagement.SubscriberDAO.contains(subscriber);
	}

	/** 
	 * Adds a media
	 * @throws MediaExistsException 
	 */
	public void addMedia(Media media) throws BadParametersException, MediaExistsException {
		if (media == null)
			throw new BadParametersException();

		// Look if the media is already in the library
		if (isAMedia(media)){
			addSpecimen(new Specimen(media));
		}
		else
			this.medias.add(media);
		
		inf.mediasManagement.MediaDAO.add(media);
	}

	/** 
	 * Remove a media
	 * @throws MediaExistsException 
	 */
	public void removeMedia(Media media) throws BadParametersException, MediaExistsException {
		if (media == null)
			throw new BadParametersException();

		this.medias.remove(media);
		inf.mediasManagement.MediaDAO.remove(media);
	}

	/**
	 */
	public void addSpecimen(Specimen specimen) throws BadParametersException, MediaExistsException{
		if (specimen == null)
			throw new BadParametersException();

		Media media = specimen.getMedia();

		if (!inf.mediasManagement.MediaDAO.contains(media))
			throw new MediaExistsException();

		media.addSpecimen(specimen);
		inf.mediasManagement.MediaDAO.addSpecimen(specimen);
	}

	public void removeSpecimen(Specimen specimen) throws BadParametersException, MediaExistsException{
		if (specimen == null)
			throw new BadParametersException();

		Media media = specimen.getMedia();
		if (!inf.mediasManagement.MediaDAO.contains(media))
			throw new MediaExistsException();

		media.removeSpecimen(specimen);
		inf.mediasManagement.MediaDAO.removeSpecimen(specimen);
	}

	public void addSubscriber(Subscriber s) throws BadParametersException, SubscriberExistsException, MediaExistsException
	{
		if (s == null)
			throw new BadParametersException();

		if (isASubscriber(s))
			throw new SubscriberExistsException();
		inf.subscribersManagement.SubscriberDAO.add(s);
		subscribers.add(s);
	}

	
	
	public void removeSubscriber(Subscriber subscriber) throws BadParametersException, SubscriberExistsException, MediaExistsException {
		if (!isASubscriber(subscriber))
			throw new SubscriberExistsException();

		this.subscribers.remove(subscriber);
		inf.subscribersManagement.SubscriberDAO.remove(subscriber);
	}

	/**
	 * @return 
	 * @throws LentMediaException 
	 * @throws BadParametersException 
	 * @throws ChildLoanException 
	 * @throws MediaExistsException 
	 * @throws SubscriberExistsException 
	 * @throws BookedSpecimenException 
	 * @throws TooManyLoansException 
	 * @throws SpecimenExistsException 
	 */
//	public void addLoan(Loan loan) throws BadParametersException {
//		if (loan == null)
//			throw new BadParametersException();
//		
//		this.loans.add(loan);
//	}
//
//	public void endLoan(Specimen specimen) throws BadParametersException, BookExistsException,
//	LentBookException, SubscriberExistsException, MediaExistsException, NotLentMediaException, BookingMediaException {
//		Loan loan = specimen.getLoan();
//		loan.returnLoan();
//	}

	public List<String> listMedias() {
		List<String> liste = new ArrayList<String>();
		for(Media media : medias){
			liste.add(media.getTitle());
		}
		return liste;
	}

	public List<String> listBooks() {
		List<String> liste = new ArrayList<String>();
		for(Media media : medias){
			if(media.getType() == "Book")
				liste.add(media.getTitle());
		}
		return liste;
	}

	public List<String> listDvds() {
		List<String> liste = new ArrayList<String>();
		for(Media media : medias){
			if(media.getType() == "Dvd")
				liste.add(media.getTitle());
		}
		return liste;
	}
	
//	public void addBooking(Booking booking) throws BadParametersException {
//		if (booking == null)
//			throw new BadParametersException();
//
//		// Check if the subscriber exists
//	
//		this.bookings.add(booking);
//	}
//
//	public void endBooking(Specimen specimen) throws BadParametersException {
//		specimen.getBooking().endBooking();
//		this.bookings.remove(specimen.getBooking());
//	}
//	

	public long getNbMedia(){
		return this.medias.size();
	}

	public long getNbSubscriber(){
		return this.subscribers.size();
	}
}
